package de.suur.jarmi.gson;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import de.suur.jarmi.common.JarmiException;
import de.suur.jarmi.common.Request;
import de.suur.jarmi.common.Response;
import de.suur.jarmi.common.Serializer;

public class GsonSerializer implements Serializer {

	private static final String CANNOT_REGISTER_TYPE_ADAPTER = "Cannot register type adapter after first call of serialize or deserialize.";
	private Gson gson;
	private GsonBuilder gsonBuilder;

	public GsonSerializer() {
		gsonBuilder = new GsonBuilder();
		gsonBuilder.registerTypeAdapter(Request.class, new RequestAdapter());
		gsonBuilder.registerTypeAdapter(Response.class, new ResponseAdapter());
	}

	private void createGson() {
		if (gson == null) {
			gson = gsonBuilder.create();
		}
	}

	@Override
	public Request deserializeRequest(byte[] data) {
		createGson();
		String jsonString = new String(data);
		return gson.fromJson(jsonString, Request.class);
	}

	@Override
	public Response deserializeResponse(byte[] data) {
		createGson();
		String jsonString = new String(data);
		return gson.fromJson(jsonString, Response.class);
	}

	public void registerTypeAdapter(Type type, Object typeAdapter) {
		if (gson == null) {
			gsonBuilder.registerTypeAdapter(type, typeAdapter);
		} else {
			throw new JarmiException(CANNOT_REGISTER_TYPE_ADAPTER);
		}
	}

	@Override
	public <T extends Serializable> byte[] serialize(T object) {
		createGson();
		String jsonString = gson.toJson(object);
		return jsonString.getBytes();
	}

	public void setTypeAdapters(Map<Type, List<Object>> typeAdapters) {
		if (gson == null) {
			for (Type type : typeAdapters.keySet()) {
				for (Object typeAdapter : typeAdapters.get(type)) {
					gsonBuilder.registerTypeAdapter(type, typeAdapter);
				}
			}
		} else {
			throw new JarmiException(CANNOT_REGISTER_TYPE_ADAPTER);
		}
	}

}
